#include <stdio.h>
#include <windows.h>
#include <stdarg.h>

static int (__stdcall *p2pcore__create_task_old)(unsigned long, const char*, long);
static unsigned char g_entrycode[] = {0x68, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x14, 0x24, 0x90, 0x90};
static unsigned char g_entrycode_old[sizeof(g_entrycode)];
static unsigned long g_entry_retip;
static unsigned long g_entry_addr;
static unsigned long g_config_debug;
static unsigned long g_config_proto;
static HINSTANCE g_hinst;

int dprintf(char * fmt, ...)
{
	va_list args;
	va_start(args, fmt);

	if(g_config_debug > 0) return vprintf(fmt, args);
	return 0;
}


long __cdecl IsLogType(unsigned long type_id)
{
	return g_config_debug > 1 ? 1 : 0;
}

void __cdecl DoLog(long unk00, unsigned long type_id, const char *str)
{
	if(g_config_debug > 1) dprintf("%s\n", str);
}

int __stdcall p2pcore__create_task(unsigned long ctx, const char *link, long task_type)
{
	dprintf(">p2pcore__create_task[%d]%s\n", task_type, link);
	if(!g_config_proto && task_type == 8) {
		p2pcore__create_task_old(ctx, link, task_type);
		return 1;
	}
	
	dprintf("---killed\n");
	return 0;
}

static unsigned long __stdcall create_p2p_core_filter(unsigned long core_ctx)
{
	DWORD oldprot;
	unsigned long tmp;
	dprintf(">>>>>>>>>core ctx: %08X\n", core_ctx);

	if(core_ctx) {
		tmp = *(unsigned long*)core_ctx + 0x14;
		VirtualProtect((LPVOID)tmp, sizeof(tmp), PAGE_READWRITE, &oldprot);
		*(unsigned long*)&p2pcore__create_task_old = *(unsigned long*)tmp;
		*(unsigned long*)tmp = (unsigned long)&p2pcore__create_task;
		VirtualProtect((LPVOID)tmp, sizeof(tmp), oldprot, &oldprot);

		dprintf("patched function create_task [%08X]\n", tmp);
	}

	return core_ctx;
}

static __declspec(naked) unsigned long __stdcall entry_ret()
{
	__asm {
		push g_entry_retip;
		push eax;
		call create_p2p_core_filter;
		retn;
	}
}

static void __stdcall patch_entry(unsigned long arg0)
{
	volatile unsigned long *retip, *entry_retip;
	DWORD oldprot;

	entry_retip = &arg0 + 1;
	retip = &arg0 - 1;

	VirtualProtect((LPVOID)g_entry_addr, sizeof(g_entrycode_old), PAGE_EXECUTE_READWRITE, &oldprot);
	memcpy((void*)g_entry_addr, g_entrycode_old, sizeof(g_entrycode_old));
	VirtualProtect((LPVOID)g_entry_addr, sizeof(g_entrycode_old), oldprot, &oldprot);

	*retip = g_entry_addr;
	g_entry_retip = *entry_retip;
	*entry_retip = (unsigned long)&entry_ret;
}

int cmain()
{
	HMODULE p2pcore;
	DWORD oldprot;
	char buf[256], fnz[256];

	g_config_proto = 0;
	g_config_debug = 0;

	GetModuleFileName(g_hinst, fnz, sizeof(fnz));
	memcpy(strrchr(fnz, '.') + 1, "ini", 4);

	if( GetPrivateProfileString("p2plog", "proto", 0, buf, sizeof(buf), fnz) > 0 && !strcmp("http", buf) )
		g_config_proto = 1;

	if( GetPrivateProfileString("p2plog", "debug", 0, buf, sizeof(buf), fnz) > 0 && atoi(buf) > 0 )
		g_config_debug = atoi(buf);

	if(g_config_debug > 0) {
		AllocConsole();
		freopen("CONOUT$", "wb", stdout);
	}

	dprintf("p2plog attached...\n");
	p2pcore = LoadLibrary("p2pcore.dll");
	g_entry_addr = (unsigned long)GetProcAddress(p2pcore, "CreateP2PCore");

	*(unsigned long*)(g_entrycode + 1) = (unsigned long)&patch_entry;
	VirtualProtect((LPVOID)g_entry_addr, sizeof(g_entrycode), PAGE_EXECUTE_READWRITE, &oldprot);
	memcpy(g_entrycode_old, (void*)g_entry_addr, sizeof(g_entrycode_old));
	memcpy((void*)g_entry_addr, g_entrycode, sizeof(g_entrycode));
	VirtualProtect((LPVOID)g_entry_addr, sizeof(g_entrycode), oldprot, &oldprot);

	return 0;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
	static int init = 0;

	switch(fdwReason)
	{ 
		case DLL_PROCESS_ATTACH:
			{
				if(!init) {
					init++;
					g_hinst = hinstDLL;
					cmain();
				}
			}
			break;
		case DLL_THREAD_ATTACH:
			break;
		case DLL_THREAD_DETACH:
			break;
		case DLL_PROCESS_DETACH:
			break;
	}

	return 1;
}
